package repository

import (
	"context"
	"errors"

	"gorm.io/gorm"

	"BookStack/internal/domain/article"
	"BookStack/internal/domain/book"
	"BookStack/internal/domain/category"
	appErrors "BookStack/pkg/errors"
)

// CategoryRepository 分类仓储实现
type CategoryRepository struct {
	db *gorm.DB
}

// NewCategoryRepository 创建分类仓储
func NewCategoryRepository(db *gorm.DB) category.Repository {
	return &CategoryRepository{
		db: db,
	}
}

// Create 创建分类
func (r *CategoryRepository) Create(ctx context.Context, c *category.Category) error {
	return r.db.WithContext(ctx).Create(c).Error
}

// Update 更新分类
func (r *CategoryRepository) Update(ctx context.Context, c *category.Category) error {
	return r.db.WithContext(ctx).Save(c).Error
}

// Delete 删除分类
func (r *CategoryRepository) Delete(ctx context.Context, id uint) error {
	return r.db.WithContext(ctx).Delete(&category.Category{}, id).Error
}

// GetByID 通过ID获取分类
func (r *CategoryRepository) GetByID(ctx context.Context, id uint) (*category.Category, error) {
	var c category.Category
	err := r.db.WithContext(ctx).First(&c, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, appErrors.New(25001, "分类不存在")
		}
		return nil, err
	}
	return &c, nil
}

// GetBySlug 通过Slug获取分类
func (r *CategoryRepository) GetBySlug(ctx context.Context, slug string) (*category.Category, error) {
	var c category.Category
	err := r.db.WithContext(ctx).Where("slug = ?", slug).First(&c).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, appErrors.New(25001, "分类不存在")
		}
		return nil, err
	}
	return &c, nil
}

// ExistsBySlug 检查Slug是否已存在
func (r *CategoryRepository) ExistsBySlug(ctx context.Context, slug string, excludeID uint) (bool, error) {
	var count int64
	query := r.db.WithContext(ctx).Model(&category.Category{}).Where("slug = ?", slug)
	if excludeID > 0 {
		query = query.Where("id != ?", excludeID)
	}
	err := query.Count(&count).Error
	return count > 0, err
}

// List 获取分类列表
func (r *CategoryRepository) List(ctx context.Context, params *category.ListParams) ([]*category.Category, int64, error) {
	var categories []*category.Category
	var total int64

	query := r.db.WithContext(ctx).Model(&category.Category{})

	// 应用类型过滤
	if params.Type >= 0 {
		query = query.Where("type = ?", params.Type)
	}

	// 应用状态过滤
	if params.Status != nil {
		query = query.Where("status = ?", *params.Status)
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 查询分页数据
	if err := query.Order("`order` ASC, id ASC").
		Offset((params.Page - 1) * params.Size).
		Limit(params.Size).
		Find(&categories).Error; err != nil {
		return nil, 0, err
	}

	return categories, total, nil
}

// GetTree 获取分类树
func (r *CategoryRepository) GetTree(ctx context.Context, categoryType int) ([]*category.Category, error) {
	var categories []*category.Category
	query := r.db.WithContext(ctx).Where("status = 1")
	if categoryType >= 0 {
		query = query.Where("type = ?", categoryType)
	}
	if err := query.Order("`order` ASC, id ASC").Find(&categories).Error; err != nil {
		return nil, appErrors.New(25009, "获取分类树失败")
	}
	return categories, nil
}

// UpdateOrder 更新分类排序
func (r *CategoryRepository) UpdateOrder(ctx context.Context, orders map[uint]int) error {
	tx := r.db.WithContext(ctx).Begin()
	for id, order := range orders {
		if err := tx.Model(&category.Category{}).
			Where("id = ?", id).
			Update("order", order).Error; err != nil {
			tx.Rollback()
			return appErrors.New(25006, "更新分类排序失败")
		}
	}
	return tx.Commit().Error
}

// UpdateContentCount 更新内容数量
func (r *CategoryRepository) UpdateContentCount(ctx context.Context, id uint, count int64) error {
	if err := r.db.WithContext(ctx).Model(&category.Category{}).
		Where("id = ?", id).
		Update("content_count", count).Error; err != nil {
		return appErrors.New(25010, "更新分类内容数量失败")
	}
	return nil
}

// GetArticleByID 获取文章
func (r *CategoryRepository) GetArticleByID(ctx context.Context, id uint) (*article.Article, error) {
	var a article.Article
	err := r.db.WithContext(ctx).First(&a, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, appErrors.New(24001, "文章不存在")
		}
		return nil, err
	}
	return &a, nil
}

// GetBookByID 获取书籍
func (r *CategoryRepository) GetBookByID(ctx context.Context, id uint) (*book.Book, error) {
	var b book.Book
	err := r.db.WithContext(ctx).First(&b, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, appErrors.New(23001, "书籍不存在")
		}
		return nil, err
	}
	return &b, nil
}

// UpdateArticleCategory 更新文章分类
func (r *CategoryRepository) UpdateArticleCategory(ctx context.Context, articleID uint, categoryID uint) error {
	return r.db.WithContext(ctx).Model(&article.Article{}).
		Where("id = ?", articleID).
		Update("category_id", categoryID).Error
}

// UpdateBookCategory 更新书籍分类
func (r *CategoryRepository) UpdateBookCategory(ctx context.Context, bookID uint, categoryID uint) error {
	return r.db.WithContext(ctx).Model(&book.Book{}).
		Where("id = ?", bookID).
		Update("category_id", categoryID).Error
}
